package com.smartwebee.android.blespp.hospital;

import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.google.gson.Gson;
import com.smartwebee.android.blespp.BleSppActivity;
import com.smartwebee.android.blespp.BluetoothLeService;
import com.smartwebee.android.blespp.CustomLoading;
import com.smartwebee.android.blespp.R;
import com.smartwebee.android.blespp.bean.XAxisData;
import com.smartwebee.android.blespp.hospital.account.LoginActivity;
import com.smartwebee.android.blespp.http.HttpRequest;
import com.smartwebee.android.blespp.http.RequestInterface;
import com.smartwebee.android.blespp.http.VolleyReqQueue;
import com.smartwebee.android.blespp.resp.BaseResp;
import com.smartwebee.android.blespp.resp.LoginResp;
import com.smartwebee.android.blespp.utils.UIUtils;
import com.smartwebee.android.blespp.utils.Utils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import static com.smartwebee.android.blespp.BleSppActivity.EXTRAS_DEVICE_ADDRESS;
import static com.smartwebee.android.blespp.BleSppActivity.EXTRAS_DEVICE_NAME;
import static com.smartwebee.android.blespp.utils.Utils.MODE_TYPE;

public class HospitalIndexActivity extends BaseActivity implements RequestInterface {
    private Double collectionCountdown = 0.5;
    private Handler handlerPostDelay = new Handler();
    private String modeType;
    private String mDeviceName;
    private String mDeviceAddress;
    private BluetoothLeService mBluetoothLeService;
    private LineChart lineChart;
    private TextView tvHead;
    private CustomLoading loadingView;
    private TextView btnNextItem;
    private boolean isFirstDisplay = true;
    private boolean isWriteToFile = true;
    //是否写入数据
    private boolean shouldGetData = false;
    //是否停止采集数据
    private boolean stopCollection = false;

    private List<Integer> p1List = new ArrayList<>();
    private List<Integer> p2List = new ArrayList<>();
    private List<Integer> r1List = new ArrayList<>();
    private List<Integer> r2List = new ArrayList<>();

    private Double p1Ave;
    private Double p2Ave;
    private Double r1Ave;
    private Double r2Ave;

    private int typePosition = 0;
    private int childPosition = 0;

    private List<Double> mode1List = new ArrayList<>();

    private XAxisData xAxisData;

    // Code to manage Service lifecycle.
    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
            // Automatically connects to the device upon successful start-up initialization.
            mBluetoothLeService.connect(mDeviceAddress);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBluetoothLeService = null;
        }
    };

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {

            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                mBluetoothLeService.connect(mDeviceAddress);
            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {

            } else if (BluetoothLeService.ACTION_GATT_SERVICES_NO_DISCOVERED.equals(action)) {
                mBluetoothLeService.connect(mDeviceAddress);
            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                if (isFirstDisplay) {
                    loadingView.setVisibility(View.GONE);
                    showReadyDialog();
                    isFirstDisplay = false;
                }
                if (shouldGetData) {
                    displayData(intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA));
                }
            } else if (BluetoothLeService.ACTION_WRITE_SUCCESSFUL.equals(action)) {
            }

        }
    };

    private void showReadyDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setCancelable(false);
        builder.setTitle("提示");
        builder.setMessage("现在开始采集初始化参数?");
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                loadingView.setVisibility(View.VISIBLE);
                loadingView.setDesc("数据初始化...");
                shouldGetData = true;
                handlerPostDelay.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        isWriteToFile = false;
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                loadingView.setVisibility(View.GONE);
                            }
                        });
                        try {
                            fetchInitParams();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }, 2000);
            }
        });
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    private void draw() throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (inputStream != null) {
            InputStreamReader inputReader = new InputStreamReader(inputStream);
            BufferedReader buffReader = new BufferedReader(inputReader);
            String line;
            //分行读取
            while ((line = buffReader.readLine()) != null) {
                if (line.startsWith("{") && line.contains("P1")) {
                    Random random = new Random();
                    if (random.nextInt(3) == 2) {
                        try {
                            JSONObject jsonObject = new JSONObject(line);
                            Integer p1 = jsonObject.getInt("P1");
                            Integer p2 = jsonObject.getInt("P2");
                            switch (modeType) {
                                case Utils.MODE_1:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_2:
//                                    Log.w("myValue", p2 - p2Ave + "");
//                                    Log.w("myLine", line);
                                    mode1List.add(Utils.getDouble3(p2 - p2Ave));
                                    break;
                                case Utils.MODE_3:
                                    mode1List.add(Utils.getDouble3(p2 - p2Ave));
                                    break;
                                case Utils.MODE_4:
                                    mode1List.add(Utils.getDouble3(p2 - p2Ave));
                                    break;
                                case Utils.MODE_5:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_6:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_7:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_8:
                                    Integer r1 = jsonObject.getInt("R1");
                                    Integer r2 = jsonObject.getInt("R2");
                                    mode1List.add(Utils.getDouble3(r2 - r1 - r2Ave + r1Ave));
                                    mode1List.add(Utils.getDouble3(p2 - p2Ave));
                                    break;
                                case Utils.MODE_9:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_10:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_11:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                                case Utils.MODE_12:
                                    mode1List.add(Utils.getDouble3(p2 - p1 - p2Ave + p1Ave));
                                    break;
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                            continue;
                        }
                    }
                }
            }
            inputStream.close();
        }
        drawToLineChart();
    }

    @Override
    public void onSuccess(String id, String resp) {
        dismissLoading();
        BaseResp baseResp = new Gson().fromJson(resp, BaseResp.class);
        if (Utils.parseData(baseResp)) {
            if (isLastItem()) {
                startActivity(new Intent(HospitalIndexActivity.this, HospitalMainActivity.class));
            } else {
                toNextItem();
            }
        }
    }

    @Override
    public void onError(String error) {
        stopCollection = true;
        dismissLoading();
        UIUtils.showToast(HospitalIndexActivity.this, error);
    }

    public class MyXFormatter implements IAxisValueFormatter {
        private List<XAxisData> datas;

        public MyXFormatter(List<XAxisData> datas) {
            this.datas = datas;
        }

        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            if (value == axis.getAxisMinimum()) {
                return datas.get(0).getFormatDate();
            }
            if (value == axis.getAxisMaximum()) {
                return datas.get(2).getFormatDate();
            }
            return datas.get(1).getFormatDate();
        }

    }

    private XAxisData getMiddleData(XAxisData startData, XAxisData endData) {
        return new XAxisData(((startData.getHours() + endData.getHours()) / 2), ((startData.getMinutes() + endData.getMinutes()) / 2), (startData.getSeconds() + endData.getSeconds()) / 2);
    }

    private void drawToLineChart() {
        if (mode1List.size() > 0) {
            List<Entry> entries = new ArrayList<>();
            XAxisData endDate = getCurrentDate();
            XAxisData middleDate = getMiddleData(xAxisData, endDate);
            for (Integer i = 0; i < mode1List.size(); i++) {
                entries.add(new Entry(i.floatValue(), mode1List.get(i).floatValue()));
            }

            LineDataSet dataSet = new LineDataSet(entries, "Label");
            dataSet.setColor(R.color.light_blue);
            dataSet.setValueTextColor(R.color.orange);
            dataSet.setLabel(Utils.getModeName(modeType));
            dataSet.setDrawCircles(false);
            dataSet.setDrawValues(false);
            dataSet.setCubicIntensity(1f);
            LineData lineData = new LineData(dataSet);
            lineChart.getXAxis().setLabelCount(2, true);
            lineChart.getXAxis().setTextSize(8);
            lineChart.getXAxis().setValueFormatter(new MyXFormatter(Arrays.asList(xAxisData, middleDate, endDate)));
            lineChart.setData(lineData);
            lineChart.invalidate();
        }
    }

    private void fetchInitParams() throws IOException {
        //初始化参数获取
        StringBuilder sb = new StringBuilder();
        InputStream instream = null;
        try {
            instream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (instream != null) {
            InputStreamReader inputreader = new InputStreamReader(instream);
            BufferedReader buffreader = new BufferedReader(inputreader);
            String line;
            //分行读取
            while ((line = buffreader.readLine()) != null) {
                if (line.startsWith("{") && line.contains("P1")) {
                    try {
                        JSONObject jsonObject = new JSONObject(line);
                        Integer p1 = jsonObject.getInt("P1");
                        Integer r1 = jsonObject.getInt("R1");
                        Integer p2 = jsonObject.getInt("P2");
                        Integer r2 = jsonObject.getInt("R2");
                        p1List.add(p1);
                        p2List.add(p2);
                        r1List.add(r1);
                        r2List.add(r2);
                    } catch (JSONException e) {
                        e.printStackTrace();
                        continue;
                    }
                    sb.append(line);
                }
            }
            instream.close();
        }
        calculateAverage();
    }

    private void calculateAverage() {
        p1Ave = getAve(p1List);
        p2Ave = getAve(p2List);
        r1Ave = getAve(r1List);
        r2Ave = getAve(r2List);
        showCollectionDialog();
    }

    private void showCollectionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("提示");
        builder.setMessage("现在开始采集运动数据?");
        builder.setCancelable(false);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                collectData(true);
            }
        });
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    private XAxisData getCurrentDate() {
        Date date = new Date();
        return new XAxisData(date.getHours(), date.getMinutes(), date.getSeconds());
    }

    /**
     * 获取蓝牙传输的数据
     *
     * @param isClear 是否清空原来file中的数据
     */
    private void collectData(boolean isClear) {
        if (isClear) {
            xAxisData = getCurrentDate();
            //清空原有数据
            mode1List.clear();
            lineChart.clear();
        }

        Utils.saveToFile(file, new byte[0], false);
        isWriteToFile = true;
        handlerPostDelay.postDelayed(new Runnable() {
            @Override
            public void run() {
                isWriteToFile = false;
                try {
                    draw();
                    if (!stopCollection) {
                        collectData(false);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }, (long) (collectionCountdown * 1000));
    }

    private Double getAve(List<Integer> p1List) {
        double sum = 0;
        for (int i = 0; i < p1List.size(); i++) {
            sum += p1List.get(i);
        }
        return sum / p1List.size();
    }

    private void displayData(byte[] buf) {
        String s = Utils.asciiToString(buf);
        if (isWriteToFile) {
            Utils.saveToFile(file, buf, true);
            Log.i(TAG, s);
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hospital_index);
        TAG = "HospitalIndexActivity";
        fetchBundle();
        initView();
        requestQueue = VolleyReqQueue.getInstance(this).getRequestQueue();

        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
        file = Utils.operationFile(this);

    }

    private void httpUploadFile(final String text) {
        showLoading();
        HttpRequest httpRequest = new HttpRequest(Request.Method.POST, Utils.uploadFile,
                this) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> map = new HashMap<String, String>();
                map.put("sn", Utils.registerResp.getData().getSn());
                map.put("pid", Utils.getModeId(modeType));
                map.put("sid", mDeviceAddress);
                map.put("starttime", xAxisData.getFormatDate());
                map.put("endtime", getCurrentDate().getFormatDate());
                map.put("text", text);
                return map;
            }
        };
        requestQueue.add(httpRequest);
    }

    private void fetchBundle() {
        //测量单个项目
        modeType = getIntent().getStringExtra(Utils.MODE_TYPE);
        mDeviceName = getIntent().getStringExtra(EXTRAS_DEVICE_NAME);
        mDeviceAddress = getIntent().getStringExtra(EXTRAS_DEVICE_ADDRESS);
        //测量计划
        if (getIntent().hasExtra(Utils.TYPE_POSITION)) {
            typePosition = getIntent().getIntExtra(Utils.TYPE_POSITION, 0);
            childPosition = getIntent().getIntExtra(Utils.CHILD_POSITION, 0);
            //最后一个项目
            if (isLastItem()) {
                findViewById(R.id.btn_next_item).setVisibility(View.GONE);
            }
        } else {
            findViewById(R.id.btn_next_item).setVisibility(View.GONE);
        }
    }

    private boolean isLastItem() {
        return (childPosition == Utils.childItem.get(typePosition).size() - 1);
    }

    private void initView() {
        btnNextItem = (TextView) findViewById(R.id.btn_next_item);
        tvHead = (TextView) findViewById(R.id.tv_head);
        tvHead.setText(Utils.getModeName(modeType));
        lineChart = (LineChart) findViewById(R.id.linechart);
        initLineChart();
        loadingView = (CustomLoading) findViewById(R.id.custom_loading);
        loadingView.setVisibility(View.VISIBLE);
        loadingView.setDesc("蓝牙连接初始化...");
        findViewById(R.id.btn_rescan).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopCollection = false;
                collectData(true);
            }
        });
        findViewById(R.id.btn_end_collect).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uploadData();
            }
        });
        findViewById(R.id.btn_back).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        btnNextItem.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uploadData();
            }
        });
    }

    private void uploadData() {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("value", new JSONArray(mode1List));
        } catch (JSONException e) {
            e.printStackTrace();
        }

        Log.i("myArray", jsonObject.toString());
        httpUploadFile(jsonObject.toString());
    }

    private void toNextItem() {
        stopCollection = true;
        childPosition++;
        final Intent intent = new Intent(HospitalIndexActivity.this, HospitalIndexActivity.class);
//                intent.putExtra(Utils.PLAN_TYPE, getIntent().getStringExtra(Utils.PLAN_TYPE));
        intent.putExtra(Utils.TYPE_POSITION, typePosition);
        intent.putExtra(Utils.CHILD_POSITION, childPosition);
        intent.putExtra(MODE_TYPE, Utils.childItem.get(typePosition).get(childPosition));
        intent.putExtra(BleSppActivity.EXTRAS_DEVICE_NAME, mDeviceName);
        intent.putExtra(BleSppActivity.EXTRAS_DEVICE_ADDRESS, mDeviceAddress);
        startActivity(intent);
        finish();
    }

    private void initLineChart() {
        lineChart.setNoDataText("暂无数据");
        Description description = new Description();
        description.setText("数据采集");
        lineChart.getAxisRight().setEnabled(false);
        lineChart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
        lineChart.setDescription(description);
        lineChart.setTouchEnabled(true);
        lineChart.setDragEnabled(true);
        lineChart.setScaleEnabled(false);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
        if (mBluetoothLeService != null) {
            final boolean result = mBluetoothLeService.connect(mDeviceAddress);
            Log.d(TAG, "Connect request result=" + result);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mGattUpdateReceiver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);
        mBluetoothLeService = null;
        handlerPostDelay.removeCallbacksAndMessages(null);
        handlerPostDelay = null;
    }

}
